import 'dart:async';

import 'package:bluetooth_protocols_parser_plugin/library.dart';
import 'package:bluetooth_protocols_parser_plugin/src/lorin/cmd/p6_cmd.dart';
import 'package:bluetooth_protocols_parser_plugin/src/lorin/integrated/p6_integrated_product_info.dart';
import 'package:bluetooth_protocols_parser_plugin/src/lorin/integrated/p6_integrated_realtime_info.dart';
import 'package:bluetooth_protocols_parser_plugin/src/lorin/lorin_protocol.dart';
import 'package:bluetooth_protocols_plugin/library.dart';

import '../lorin_helper.dart';
import '../realtime/battery/p6_realtime_battery_info.dart';
import '../realtime/error/p6_realtime_error.dart';
import '../realtime/info/p6_realtime_info.dart';
import '../realtime/info/p6_realtime_all_info.dart';
import '../realtime/status/p6_realtime_status.dart';
import '../../response/lorin_response_data.dart';
import '../settings/p6_settings.dart';
import '../statistics/p6_statistics_once_data.dart';
import '../statistics/p6_statistics_total_data.dart';

class P6Protocol extends LorinProtocol<
    P6RealtimeInfo,
    P6RealtimeStatus,
    P6RealtimeError,
    P6RealtimeAllInfo,
    P6RealtimeBatteryInfo,
    P6StatisticsOnceData,
    P6StatisticsTotalData,
    P6Settings,
    P6IntegratedProductInfo,
    P6IntegratedRealtimeInfo,
    LorinResponseData> {
  @override
  LorinPrivateIntructionMessage get privateInstrMessage =>
      _P6PrivateIntructionMessage();

  //
  // 蓝牙主动响应监听
  StreamSubscription? _bluetoothNotifyStreamSubscription;

  @override
  Future<P6RealtimeInfo> getRealtimeInfo() {
    return sendRequest(privateInstrMessage.getRealtimeInfoIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para == null) {
        throw Exception('Get P6RealtimeInfo failed');
      }
      return P6RealtimeInfo.fromBytes(msg.data!.para!);
    });
  }

  @override
  Future<P6RealtimeStatus> getRealtimeStatus() {
    return sendRequest(privateInstrMessage.getRealtimeStatusIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return P6RealtimeStatus.fromBytes(msg.data!.para!);
      }
      throw Exception('Get P6RealtimeStatus failed');
    });
  }

  @override
  Future<P6RealtimeError> getRealtimeError() {
    return sendRequest(privateInstrMessage.getRealtimeErrorIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return P6RealtimeError.fromBytes(msg.data!.para!);
      }
      throw Exception('Get P6RealtimeError failed');
    });
  }

  @override
  Future<P6RealtimeAllInfo> getRealtimeAll() {
    return sendRequest(privateInstrMessage.getRealtimeAllIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return P6RealtimeAllInfo.fromBytes(msg.data!.para!);
      }
      throw Exception('Get P6RealtimeAllInfo failed');
    });
  }

  @override
  Future<P6Settings> getSettingsAll() {
    return sendRequest(privateInstrMessage.getSettingsAllIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return P6Settings.fromBytes(msg.data!.para!);
      }
      throw Exception('Get P6Settings failed');
    });
  }

  @override
  Future<P6StatisticsOnceData> getStatisticOnce({int? startIndex, int? count}) {
    return sendRequest(privateInstrMessage
            .getStatisticOnceIntrMsg(startNum: startIndex, count: count)
            .toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return P6StatisticsOnceData.fromBytes(msg.data!.para!);
      }
      throw Exception('Get P6StatisticsOnceData failed');
    });
  }

  @override
  Future<P6StatisticsTotalData> getStatisticsTotal() {
    return sendRequest(
            privateInstrMessage.getStatisticsTotalIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return P6StatisticsTotalData.fromBytes(msg.data!.para!);
      }
      throw Exception('Get P6StatisticsTotalData failed');
    });
  }

  @override
  Future<P6RealtimeBatteryInfo> getRealtimeBatteryInfo() {
    return sendRequest(
            privateInstrMessage.getRealtimeBatteryInfoIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return P6RealtimeBatteryInfo.fromBytes(msg.data!.para!);
      }
      throw Exception('Get P6RealtimeBatteryInfo failed');
    });
  }

  @override
  Future<P6IntegratedProductInfo> getIntegratedProductInfo() {
    return sendRequest(
            privateInstrMessage.getIntegratedProductInfoIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return P6IntegratedProductInfo.fromBytes(msg.data!.para!);
      }
      throw Exception('Get P6IntegratedProductInfo failed');
    });
  }

  @override
  Future<P6IntegratedRealtimeInfo> getIntegratedRealtimeInfoAll() {
    return sendRequest(
            privateInstrMessage.getIntegratedRealtimeInfoAllIntrMsg().toBytes())
        .then((rspMsg) {
      LorinMessage msg = LorinMessage.fromList(rspMsg);
      if (msg.data!.para != null) {
        return P6IntegratedRealtimeInfo.fromBytes(msg.data!.para!);
      }
      throw Exception('Get P6IntegratedRealtimeInfo failed');
    });
  }

  @override
  void cancelBluetoothNotifyStream() {
    _bluetoothNotifyStreamSubscription?.cancel();
    _bluetoothNotifyStreamSubscription = null;
  }

  @override
  void listenBluetoothNotifyStream(
      {Function(LorinResponseData p1)? callbackNfcCardPairSuccess,
      Function(P6RealtimeInfo p1)? callbackRealtimeInfo,
      Function(P6IntegratedRealtimeInfo p1)? callbackRealtimeAllInfo}) {
    _bluetoothNotifyStreamSubscription?.cancel();
    _bluetoothNotifyStreamSubscription = responseNotifyStream?.listen((data) {
      LorinMessage? lorinMessages = LorinHelper.bytesToLorinMessage(data);
      if (lorinMessages != null &&
          lorinMessages.data != null &&
          lorinMessages.data!.para != null &&
          callbackRealtimeAllInfo != null) {
        callbackRealtimeAllInfo(
            P6IntegratedRealtimeInfo.fromBytes(lorinMessages.data!.para!));
      }
    });
  }
}

class _P6PrivateIntructionMessage extends LorinPrivateIntructionMessage {
  @override
  get privateRequestBody => _P6PrivateRequestBody();
}

class _P6PrivateRequestBody extends LorinPrivateRequestBody {
  @override
  LorinCmdBase get cmdBase => P6Cmd();

  @override
  int get defaultTargetDevice => TargetDeviceType.eucHmic.rawValue;
}
